package org.jsola.hr.service.impl;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.StopWatch;
import com.alibaba.excel.EasyExcel;
import com.github.pagehelper.PageHelper;
import io.swagger.annotations.ApiParam;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileItemFactory;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.jboss.marshalling.ByteInputStream;
import org.jsola.admin.entity.SiteDO;
import org.jsola.common.*;
import org.jsola.core.Page;
import org.jsola.core.entity.BaseDO;
import org.jsola.exception.ParamException;
import org.jsola.hr.common.CustomCellWriteHandler;
import org.jsola.hr.common.ExampleKit;
import org.jsola.hr.common.ExcelKit;
import org.jsola.hr.constant.HrConstants;
import org.jsola.hr.dao.IChannelDAO;
import org.jsola.hr.dto.ChannelAddDTO;
import org.jsola.hr.dto.ChannelUpdateDTO;
import org.jsola.hr.dto.excel.ChannelInfoImportDTO;
import org.jsola.hr.dto.excel.EmpInfoImportDTO;
import org.jsola.hr.dto.user.AddUserDTO;
import org.jsola.hr.entity.*;
import org.jsola.hr.exception.HrException;
import org.jsola.hr.provider.*;
import org.jsola.hr.query.*;
import org.jsola.hr.service.*;
import org.jsola.hr.service.excel.ChannelInfoImportListener;
import org.jsola.hr.vo.*;
import org.jsola.hr.vo.excel.ChannelInfoExportVO;
import org.jsola.permission.entity.RoleMemberDO;
import org.jsola.recruit2.dto.BrokerAddDTO;
import org.jsola.salary.common.CalendarKit;
import org.jsola.salary.entity.ChannelFeeSettlementDO;
import org.jsola.salary.query.ChannelFeeSettlementQuery;
import org.jsola.salary.vo.ChannelFeeSum;
import org.jsola.user.core.TokenUser;
import org.jsola.user.dto.UserAddDTO;
import org.jsola.user.entity.UserDO;
import org.jsola.user.query.UserQuery;
import org.jsola.user.vo.UserListVO;
import org.jsola.user.vo.UserVO;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.commons.CommonsMultipartFile;
import tk.mybatis.mapper.entity.Example;

import java.io.*;
import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.Stream;

/**
 * 渠道管理
 *
 * @author zhr
 */
@Slf4j
@Service("hrChannelServiceImpl")
public class ChannelServiceImpl implements IChannelService {

    @Autowired
    private IChannelDAO channelDAO;
    @Autowired
    private ICheckInPeopleService checkInPeopleService;
    @Autowired
    private IEmpInfoService empInfoService;
    @Autowired
    private IAdminProviderService adminProviderService;
    @Autowired
    private IUserProviderService userProviderService;
    @Autowired
    private IHrPermissionService hrPermissionService;
    @Autowired
    private IChildCompanyService childCompanyService;
    @Autowired
    private IPermissionProviderService permissionProviderService;
    @Autowired
    private IChannelCompanyService channelCompanyService;
    @Autowired
    private IUserRoleCompanyService userRoleCompanyService;
    @Autowired
    private IBrokerProviderService brokerProviderService;
    @Autowired
    private IFileProviderService fileProviderService;
    @Autowired
    private IChannelGroupJurisdictionService channelGroupJurisdictionService;
    @Autowired
    private IChannelGroupUserService channelGroupUserService;
    @Autowired
    private IChannelGroupService channelGroupService;

    @Autowired
    private ISalaryProviderService salaryProviderService;

    @Override
    public ChannelFeeSum feeSum(ChannelFeeSettlementQuery channelFeeSettlementQuery, TokenUser tokenUser) {
        // 指定月合计
        ChannelFeeSum channelFeeSum = feeSumByYearAndMonth(channelFeeSettlementQuery, tokenUser);
        if (null == channelFeeSum) {
            return null;
        }
        Calendar lastMonth = CalendarKit.getLastMonth(channelFeeSettlementQuery.getYearly(), channelFeeSettlementQuery.getMonthly());
        int year = lastMonth.get(Calendar.YEAR);
        int month = lastMonth.get(Calendar.MONTH) + 1;
        // 上个月的合计
        channelFeeSettlementQuery.setYearly(year);
        channelFeeSettlementQuery.setMonthly(month);
        ChannelFeeSum LastChannelFeeSum = feeSumByYearAndMonth(channelFeeSettlementQuery, tokenUser);
        // 人数变化量
        Integer countChange = 0;
        // 费用合计变化
        BigDecimal sumChange = BigDecimal.ZERO;
        //  上个月为空
        if (null == LastChannelFeeSum) {
            countChange = channelFeeSum.getFeePeopleCount();
            sumChange = channelFeeSum.getFeeSum();
        } else {
            countChange = channelFeeSum.getFeePeopleCount() - LastChannelFeeSum.getFeePeopleCount();
            sumChange = channelFeeSum.getFeeSum().subtract(LastChannelFeeSum.getFeeSum());
        }

        channelFeeSum.setCountChange(countChange);
        channelFeeSum.setSumChange(sumChange);
        return channelFeeSum;
    }

    @Override
    public void updatePhone(String userId, String phone) {
        ChannelDO channelDO = new ChannelDO();
        channelDO.setPhone(phone);

        Example example = new Example(ChannelDO.class);
        example.and().andEqualTo("adminUserId", userId)
                        .andEqualTo("valid", true);

        channelDAO.updateByExampleSelective(channelDO, example);
    }

    /**
     * 查询指定年月的合计
     *
     * @param channelFeeSettlementQuery
     * @param tokenUser
     * @return
     */
    private ChannelFeeSum feeSumByYearAndMonth(ChannelFeeSettlementQuery channelFeeSettlementQuery, TokenUser tokenUser) {
        ChannelFeeSum channelFeeSum = new ChannelFeeSum();
        List<ChannelFeeSettlementDO> channelFeeSettlementDOS = salaryProviderService.feeSumByYearAndMonth(channelFeeSettlementQuery, tokenUser);
        if (CollectionUtils.isEmpty(channelFeeSettlementDOS)) {
            return null;
        }
        //查询选定二级分组所有的渠道
        if (channelFeeSettlementQuery.getLevel() == 2) {
            if (CollectionUtils.isEmpty(channelFeeSettlementQuery.getChannelGroupIdList())) {
                return null;
            } else {
                List<String> channelIds = selectByGroupIds(channelFeeSettlementQuery.getChannelGroupIdList(), tokenUser).stream().map(ChannelDO::getId).collect(Collectors.toList());
                channelFeeSettlementDOS.removeIf(channelFeeSettlementDO -> !channelIds.contains(channelFeeSettlementDO.getChannelId()));
            }
        }
        // 渠道总数
        int channelCount = channelFeeSettlementDOS.size();
        // 渠道产生费用人数
        int peopleCount = 0;
        // 应付渠道费用总数
        BigDecimal feeSum = BigDecimal.ZERO;
        for (ChannelFeeSettlementDO channelFeeSettlementDO : channelFeeSettlementDOS) {
            feeSum = feeSum.add(channelFeeSettlementDO.getSumTotalFee());
            peopleCount += channelFeeSettlementDO.getFeePeopleNumber();
        }
        channelFeeSum.setChannelCount(channelCount);
        channelFeeSum.setFeePeopleCount(peopleCount);
        channelFeeSum.setFeeSum(feeSum);
        return channelFeeSum;
    }


    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public Page<ChannelListVO> pageChannelList(ChannelQuery channelQuery, TokenUser tokenUser) {
        if (channelQuery.getLevel() == 1) {
            //查询当前的分组权限
            Integer myJurisdiction = channelGroupJurisdictionService.getMyJurisdiction(tokenUser);
            if (myJurisdiction == 0 || myJurisdiction == 2) {
                channelQuery.setIsAll(true);
            } else {
                channelQuery.setIsAll(false);
                //查询自己可以管理的组
                List<String> groupIdList = new ArrayList<>();
                if (myJurisdiction == 1) {
                    groupIdList.add(HrConstants.DEFAULT.toUpperCase());
                }
                List<ChannelGroupUserDO> channelGroupUserDOList = channelGroupUserService.selectGroupByUserId(tokenUser.getUserId(), tokenUser);
                if (!CollectionUtils.isEmpty(channelGroupUserDOList)) {
                    List<String> groups = channelGroupUserDOList.stream().map(ChannelGroupUserDO::getChannelGroupId).collect(Collectors.toList());
                    groupIdList.addAll(groups);
                }
                //添加一个特殊id保证list不为空，否则不会进行筛选
                groupIdList.add("test");
                channelQuery.setChannelGroupIdList(groupIdList);
            }
        }
        com.github.pagehelper.Page<ChannelListVO> page1 = PageHelper.startPage(channelQuery.getPageNo(), channelQuery.getPageSize());
        List<ChannelListVO> channelVOList = channelDAO.pageChannelList(channelQuery, tokenUser.getSiteId());
        //查询渠道的公司
        List<String> channelIds = channelVOList.stream().map(ChannelListVO::getId).collect(Collectors.toList());
        List<ChannelCompanyVO> channelCompanyVOS = channelCompanyService.selectByChannelIds(channelIds, tokenUser.getSiteId());
        if (!CollectionUtils.isEmpty(channelCompanyVOS)) {
            Map<String, List<ChannelCompanyVO>> listMap = channelCompanyVOS.stream().collect(Collectors.groupingBy(ChannelCompanyVO::getChannelId));
            for (ChannelListVO channelListVO : channelVOList) {
                if (!listMap.containsKey(channelListVO.getId())) {
                    continue;
                }
                List<ChannelCompanyVO> channelCompanyVOS1 = listMap.get(channelListVO.getId());
                if (channelCompanyVOS1.size() == 1 && channelCompanyVOS1.get(0).getIsAllChildCompany()) {
                    channelListVO.setIsAllChildCompany(true);
                } else {
                    List<String> companyIds = channelCompanyVOS1.stream().map(ChannelCompanyVO::getEmployerId).collect(Collectors.toList());
                    channelListVO.setIsAllChildCompany(false);
                    channelListVO.setCompanyIds(companyIds);
                }
            }
        }
        return new Page<>(channelVOList, channelQuery.getPageNo(), channelQuery.getPageSize(), (int) page1.getTotal());
    }

    @Override
    public List<ChannelDO> selectByGroupIds(List<String> channelGroupIds, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(channelGroupIds)) {
            return new ArrayList<>();
        }
        Example example = new Example(ChannelDO.class);
        example.and()
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andEqualTo("valid", true)
                .andIn("channelGroupId", channelGroupIds);
        return channelDAO.selectByExample(example);
    }

    @Override
    public List<ChannelDO> selectByGroupId(String channelGroupId, TokenUser tokenUser) {
        // 检查名称及电话是否重复
        Example example = new Example(ChannelDO.class);
        example.and()
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andEqualTo("valid", true)
                .andEqualTo("channelGroupId", channelGroupId);
        return channelDAO.selectByExample(example);
    }


    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public Integer synchronizationBroker(String[] channelIds, TokenUser tokenUser) {
        for (String channelId : channelIds) {
            ChannelVO channelVO = selectById(channelId, tokenUser.getSiteId());
            if (channelVO == null) {
                continue;
            }
            if (StringUtils.isEmpty(channelVO.getName()) || StringUtils.isEmpty(channelVO.getPhone())) {
                continue;
            }
            BrokerAddDTO brokerAddDTO = new BrokerAddDTO();
            brokerAddDTO.setName(channelVO.getName());
            brokerAddDTO.setCode(channelVO.getIdcard());
            brokerAddDTO.setPhone(channelVO.getPhone());
            brokerAddDTO.setAddType(2);
            brokerProviderService.save(brokerAddDTO, tokenUser);
        }
        return null;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public ChannelVO save(ChannelAddDTO channelAddDTO, Boolean isException, TokenUser tokenUser) {
        // 检查名称及电话是否重复
        Example example = new Example(ChannelDO.class);
        example.and()
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andEqualTo("valid", true)
                .andEqualTo("name", channelAddDTO.getName());
        example.or(example.createCriteria()
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andEqualTo("valid", true)
                .andEqualTo("phone", channelAddDTO.getPhone()));
        List<ChannelDO> channelDOList = channelDAO.selectByExample(example);
        if (!CollectionUtils.isEmpty(channelDOList)) {
            if (isException) {
                throw new ParamException("名称:" + channelAddDTO.getName()
                        + " 或 电话:" + channelAddDTO.getPhone() + "重复，新增失败！");
            } else {
                return null;
            }
        }
        // 新增用户角色
        AddUserDTO addUserDTO = new AddUserDTO();
        addUserDTO.setName(channelAddDTO.getUserName());
        addUserDTO.setPhone(channelAddDTO.getPhone());
        addUserDTO.setPassword(channelAddDTO.getPassword());
        addUserDTO.setHrRoleId(channelAddDTO.getHrRoleId());
        addUserDTO.setChildCompanyIdList(channelAddDTO.getChildCompanyIdList());
        addUserDTO.setEmployerIdList(channelAddDTO.getEmployerIdList());
        addUserDTO.setIsAllChildCompany(channelAddDTO.getIsAllChildCompany());
        UserVO userVO = userProviderService.saveChannelUser(addUserDTO, tokenUser);
        ParamException.notNull(userVO, "新建角色失败，请稍后重试或联系管理员!");
        // 转DO
        ChannelDO channelDO = channelAddDTO.to(ChannelDO.class);
        // 添加管理员id
        channelDO.setAdminUserId(userVO.getId());
        // 保存
        channelDO = save(channelDO, tokenUser.getSiteId(), tokenUser.getUserId());
        // 保存渠道和用工单位/用工单位分组的关系

        channelCompanyService.saveChannel(channelDO.getId(), addUserDTO.getIsAllChildCompany()
                , addUserDTO.getChildCompanyIdList(), addUserDTO.getEmployerIdList(), tokenUser);
        return channelDO.to(ChannelVO.class);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public ChannelImportExcelVO importChannel(File file, TokenUser tokenUser) {
        ChannelInfoImportListener channelInfoImportListener = new ChannelInfoImportListener();
        channelInfoImportListener.setTokenUser(tokenUser);
        channelInfoImportListener.setParseOnly(false);
        // 读取excel入库
        EasyExcel.read(file, ChannelInfoImportDTO.class, channelInfoImportListener).sheet().doRead();
//        if (channelInfoImportListener.getSuccessCount() == 0) {
//            throw new ParamException("没有数据导入成功，请检查数据是否有误!");
//        }
        ChannelImportExcelVO channelImportExcelVO = channelInfoImportListener.getChannelImportExcelVO();
        if (!CollectionUtils.isEmpty(channelImportExcelVO.getImportFil())) {
            //保存错误数据
            String filenames = exportFailData(channelImportExcelVO.getImportFil(), tokenUser);
            channelImportExcelVO.setFailPath(filenames);
        }
        return channelImportExcelVO;
    }

    private String exportFailData(List<ChannelInfoImportDTO> importFil, TokenUser tokenUser) {
        // 表头容器定义
        List<List<String>> headList = new ArrayList<>();
        // 所有的数据容器定义
        List<List<String>> dataList = new ArrayList<>();
        String[] strings = {"错误信息", "所属分组", "渠道名称", "联系电话", "所在地区", "身份证号", "银行卡号"};
        for (String head : strings) {
            List<String> headList1 = new ArrayList<>();
            headList1.add(head);
            headList.add(headList1);
        }
        for (ChannelInfoImportDTO channelInfoImportDTO : importFil) {
            ArrayList<String> dataList1 = new ArrayList<>();
            if (StringUtils.isEmpty(channelInfoImportDTO.getErrorReason())) {
                dataList1.add("");
            } else {
                dataList1.add(channelInfoImportDTO.getErrorReason());
            }
            if (StringUtils.isEmpty(channelInfoImportDTO.getGroupName())) {
                dataList1.add("");
            } else {
                dataList1.add(channelInfoImportDTO.getGroupName());
            }
            if (StringUtils.isEmpty(channelInfoImportDTO.getName())) {
                dataList1.add("");
            } else {
                dataList1.add(channelInfoImportDTO.getName());
            }
            if (StringUtils.isEmpty(channelInfoImportDTO.getPhone())) {
                dataList1.add("");
            } else {
                dataList1.add(channelInfoImportDTO.getPhone());
            }
            if (StringUtils.isEmpty(channelInfoImportDTO.getAddress())) {
                dataList1.add("");
            } else {
                dataList1.add(channelInfoImportDTO.getAddress());
            }
            if (StringUtils.isEmpty(channelInfoImportDTO.getIdcard())) {
                dataList1.add("");
            } else {
                dataList1.add(channelInfoImportDTO.getIdcard());
            }
            if (StringUtils.isEmpty(channelInfoImportDTO.getBankNo())) {
                dataList1.add("");
            } else {
                dataList1.add(channelInfoImportDTO.getBankNo());
            }
            dataList.add(dataList1);
        }

        // 导出excel
        String tempPath = FileKit.getSystemTempPath();
        boolean mkdir = new File(tempPath).mkdir();
        String tempFilePath = tempPath + "渠道导入错误数据.xlsx";
        BufferedOutputStream bos = null;
        try {
            boolean newFile = new File(tempFilePath).createNewFile();
            bos = new BufferedOutputStream(new FileOutputStream(tempFilePath));
            EasyExcel.write(bos)
                    .head(headList)
                    .registerWriteHandler(new CustomCellWriteHandler())
                    .sheet("渠道导入错误数据")
                    .doWrite(dataList);
        } catch (IOException e) {
            e.printStackTrace();
        }
        File file = new File(tempFilePath);
        FileItem fileItem = createFileItem(file);
        CommonsMultipartFile[] commonsMultipartFiles = new CommonsMultipartFile[1];
        commonsMultipartFiles[0] = new CommonsMultipartFile(fileItem);
        String fileName = "";
        String format = DateUtil.format(new Date(), "yyyy.MM.dd");
        fileName = "渠道导入错误数据-" + format;
        List<String> list =
                fileProviderService.uploadAndSetName(commonsMultipartFiles, "inline", fileName, tokenUser);
        if (!CollectionUtils.isEmpty(list)) {
            return list.get(0);
        }
        return null;
    }

    /**
     * File 转 FileItem
     */
    private FileItem createFileItem(File file) {
        FileItemFactory factory = new DiskFileItemFactory(16, null);
        FileItem item = factory.createItem("textField", "text/plain", true, file.getName());
        int bytesRead;
        byte[] buffer = new byte[8192];
        try {
            FileInputStream fis = new FileInputStream(file);
            OutputStream os = item.getOutputStream();
            while ((bytesRead = fis.read(buffer, 0, 8192)) != -1) {
                os.write(buffer, 0, bytesRead);
            }
            os.close();
            fis.close();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return item;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int update(ChannelUpdateDTO channelUpdateDTO, TokenUser tokenUser) {
        // 检查要修改的名称是否存在
        ChannelDO oldChannelDO = this.selectDOById(channelUpdateDTO.getId(), tokenUser.getSiteId());
        ParamException.notNull(oldChannelDO, "该数据不存在或已被删除，请刷新重试!");
        if (oldChannelDO.getName() != null && !oldChannelDO.getName().equals(channelUpdateDTO.getName())) {
            // 检查名称是否重复
            Example example = new Example(ChannelDO.class);
            example.and()
                    .andEqualTo("siteId", tokenUser.getSiteId())
                    .andEqualTo("valid", true)
                    .andEqualTo("name", channelUpdateDTO.getName());
            List<ChannelDO> channelDOList = channelDAO.selectByExample(example);
            ParamException.isTrue(CollectionUtils.isEmpty(channelDOList), "名称重复，修改失败！");
        }
        if (oldChannelDO.getPhone() != null && !oldChannelDO.getPhone().equals(channelUpdateDTO.getPhone())) {
            // 检查名称是否重复
            Example example = new Example(ChannelDO.class);
            example.and()
                    .andEqualTo("siteId", tokenUser.getSiteId())
                    .andEqualTo("valid", true)
                    .andEqualTo("phone", channelUpdateDTO.getPhone());
            List<ChannelDO> channelDOList = channelDAO.selectByExample(example);
            ParamException.isTrue(CollectionUtils.isEmpty(channelDOList), "已有渠道的联系电话与此相同，修改失败");
            //判断登录手机号是否需要修改
            if (!oldChannelDO.getPhone().equals(channelUpdateDTO.getPhone())) {
                //查询新手机是否有对应user
                UserDO userDO = userProviderService.selectByPhone(channelUpdateDTO.getPhone());
                UserDO oldUser = userProviderService.selectByPhone(oldChannelDO.getPhone());
                if (userDO == null) {
                    //新增user
                    AddUserDTO addUserDTO = oldUser.to(AddUserDTO.class);
                    addUserDTO.setPhone(channelUpdateDTO.getPhone());
                    UserVO userVO = userProviderService.saveChannelUser(addUserDTO, tokenUser);
                    channelUpdateDTO.setAdminUserId(userVO.getId());
                } else {
                    channelUpdateDTO.setAdminUserId(userDO.getId());
                }

            }
        }
        //转DO
        ChannelDO channelDO = channelUpdateDTO.to(ChannelDO.class);
        //根据主键更新，只更新非null值
        int update = updateByIdSelective(channelDO, tokenUser.getSiteId(), tokenUser.getUserId());

        // 修改分管用工单位
        channelCompanyService.saveOrUpdateChannel(channelUpdateDTO.getId(), channelUpdateDTO.getIsAllChildCompany()
                , channelUpdateDTO.getChildCompanyIdList(), channelUpdateDTO.getEmployerIdList(), tokenUser);
        return update;
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public int deleteByIds(TokenUser tokenUser, String... channelIds) {
        for (String channelId : channelIds) {
            // 修改该渠道人员的渠道id为null;
            List<CheckInPeopleDO> checkInPeopleDOList = checkInPeopleService.selectListByChannelId(channelId,
                    tokenUser.getSiteId());
            for (CheckInPeopleDO checkInPeopleDO : checkInPeopleDOList) {
                checkInPeopleDO.setChannelId(null);
                checkInPeopleService.updateIncludeNull(checkInPeopleDO, tokenUser);
            }
        }
        return logicalDeleteByIds(tokenUser.getSiteId(), tokenUser.getUserId(), (Object[]) channelIds);
    }


    @Override
    public ChannelVO selectById(String channelId, String siteId) {
        ChannelDO channelDO = selectDOById(channelId, siteId);
        if (channelDO == null) {
            return null;
        }
        return channelDO.to(ChannelVO.class);
    }

    @Override
    public List<ChannelVO> selectByIds(List<String> channelIds, String siteId) {
        if (CollectionUtils.isEmpty(channelIds)) {
            return new ArrayList<>();
        }
        Example example = new Example(ChannelDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andIn("id", channelIds);
        List<ChannelDO> channelDOS = channelDAO.selectByExample(example);
        List<ChannelVO> channelVOS = new ArrayList<>();
        if (!CollectionUtils.isEmpty(channelDOS)) {
            channelVOS = channelDOS.stream().map(s -> s.to(ChannelVO.class)).collect(Collectors.toList());
        }
        return channelVOS;
    }

    @Override
    public List<ChannelListVO> select(ChannelQuery channelQuery, String siteId) {
        List<ChannelDO> channelDOList = selectDO(channelQuery, siteId);
        if (CollectionUtils.isEmpty(channelDOList)) {
            return channelDOList == null ? null : new ArrayList<>();
        }
        return channelDOList.stream()
                .map(channelDO -> channelDO.to(ChannelListVO.class))
                .collect(Collectors.toList());
    }

    @Override
    public int selectCount(ChannelQuery channelQuery, String siteId) {
        Example example = buildExample(channelQuery, siteId);
        return channelDAO.selectCountByExample(example);
    }

    @Override
    public Page<ChannelListVO> selectPage(ChannelQuery channelQuery, String siteId) {
        Example example = buildExample(channelQuery, siteId);
        Page<ChannelDO> page = channelDAO.selectPageByExample(example,
                channelQuery.getPageNo(),
                channelQuery.getPageSize());

        return page.to(ChannelListVO.class);
    }

    @Override
    public Page<ChannelListVO> selectPageAndCompany(ChannelQuery channelQuery, String siteId) {
        Example example = buildExample(channelQuery, siteId);
        Page<ChannelDO> page = channelDAO.selectPageByExample(example,
                channelQuery.getPageNo(),
                channelQuery.getPageSize());
        List<ChannelDO> channelDOList = page.getEntities();
        if (CollectionUtils.isEmpty(channelDOList)) {
            return new Page<>(new ArrayList<>(), channelQuery.getPageNo(), channelQuery.getPageSize(), 0);
        }
        // 查询渠道分管用工单位
        List<String> channelIds = channelDOList.parallelStream().map(BaseDO::getId).collect(Collectors.toList());
        List<ChannelCompanyVO> channelCompanyVOList = channelCompanyService.selectByChannelIds(channelIds, siteId);
        Map<String, List<ChannelCompanyVO>> channelIdCompanyMap = channelCompanyVOList.parallelStream()
                .collect(Collectors.groupingBy(ChannelCompanyVO::getChannelId));
        List<ChannelListVO> channelListVOList = channelDOList.parallelStream().map(channelDO -> {
            ChannelListVO channelListVO = channelDO.to(ChannelListVO.class);
            // 分管的用工单位
            List<ChannelCompanyVO> channelCompanyList = channelIdCompanyMap.get(channelDO.getId());
            if (!CollectionUtils.isEmpty(channelCompanyList)) {
                // 是否有总公司权限
                if (channelCompanyList.parallelStream().anyMatch(ChannelCompanyVO::getIsAllChildCompany)) {
                    // 有全部用工单位权限
                    channelListVO.setIsAllChildCompany(true);
                } else {
                    List<String> groupIds = new ArrayList<>();
                    List<String> companyIds = new ArrayList<>();
                    for (ChannelCompanyVO channelCompanyVO : channelCompanyList) {
                        if (channelCompanyVO.getIsAllEmployer()) {
                            groupIds.add(channelCompanyVO.getChildCompanyId());
                        } else {
                            companyIds.add(channelCompanyVO.getEmployerId());
                        }
                    }
                    channelListVO.setIsAllChildCompany(false);
                    channelListVO.setGroupIds(groupIds);
                    channelListVO.setCompanyIds(companyIds);
                }
            } else {
                channelListVO.setIsAllChildCompany(false);
                channelListVO.setGroupIds(new ArrayList<>());
                channelListVO.setCompanyIds(new ArrayList<>());
            }
            return channelListVO;
        }).collect(Collectors.toList());
        return new Page<>(channelListVOList, page.getPageNo(), page.getPageSize(), page.getEntityCount());
    }

    @Override
    public ChannelDO selectDOById(String channelId, String siteId) {
        return listById(channelId, siteId);
    }

    @Override
    public List<ChannelDO> selectDO(ChannelQuery channelQuery, String siteId) {
        Example example = buildExample(channelQuery, siteId);
        return channelDAO.selectByExample(example);
    }

    @Override
    public Integer selectCountByChannelId(String channelId, TokenUser tokenUser) {
        ParamException.notNull(channelId, "channelVO不能为空");
        CheckInPeopleQuery checkInPeopleQuery = new CheckInPeopleQuery();
        checkInPeopleQuery.setChannelId(channelId);
        return checkInPeopleService.selectCount(checkInPeopleQuery, tokenUser.getSiteId());
    }

    @Override
    public void selectCountByChannelIdList(List<ChannelListVO> list, TokenUser tokenUser) {
        if (CollectionUtils.isEmpty(list)) {
            return;
        }
        List<String> channelIdList = list.parallelStream().map(ChannelListVO::getId).collect(Collectors.toList());
        Map<String, Integer> countMap = checkInPeopleService.selectCount(channelIdList, tokenUser.getSiteId());
        if (!CollectionUtils.isEmpty(countMap)) {
            list.forEach(s -> {
                Integer count = countMap.get(s.getId());
                if (Objects.nonNull(count)) {
                    s.setNumberPeople(count);
                }
            });
        }
    }

    @Override
    public Integer selectCountByChannelGroupId(String channelGroupId, TokenUser tokenUser) {
        ParamException.notNull(channelGroupId, "channelGroupId不能为空");
        ChannelQuery channelQuery = new ChannelQuery();
        channelQuery.setChannelGroupId(channelGroupId);
        return selectCount(channelQuery, tokenUser.getSiteId());
    }

    @Override
    public ChannelVO selectByPhone(String phone, String siteId) {
        if (StrKit.isEmpty(phone)) {
            return null;
        }
        CheckInPeopleDO checkInPeopleDO = checkInPeopleService.selectByPhone(phone, siteId);
        if (null == checkInPeopleDO) {
            return null;
        }
        return selectById(checkInPeopleDO.getChannelId(), siteId);
    }

    @Override
    public ChannelVO selectByName(String name, String siteId) {
        Example example = new Example(ChannelDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andEqualTo("name", name);
        List<ChannelDO> channelDOList = channelDAO.selectByExample(example);
        if (CollectionUtils.isEmpty(channelDOList)) {
            return null;
        }
        return channelDOList.get(0).to(ChannelVO.class);
    }

    @Override
    public List<ChannelDO> selectByNameList(List<String> nameList, String siteId) {
        if (CollectionUtils.isEmpty(nameList)) {
            return new ArrayList<>();
        }
        Example example = new Example(ChannelDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId)
                .andIn("name", nameList);
        return channelDAO.selectByExample(example);
    }

    @Override
    public List<ChannelVO> selectByPhones(List<String> phones, String siteId) {
        if (CollectionUtils.isEmpty(phones)) {
            return new ArrayList<>();
        }
        List<CheckInPeopleDO> checkInPeopleDOS = checkInPeopleService.selectByPhones(phones, siteId);
        if (CollectionUtils.isEmpty(checkInPeopleDOS)) {
            return new ArrayList<>();
        }
        List<String> channelIdList = checkInPeopleDOS.parallelStream()
                .map(CheckInPeopleDO::getChannelId).collect(Collectors.toList());
        return selectByIds(channelIdList, siteId);
    }

    @Override
    public ChannelVO selectByEmpId(String empId, String siteId) {
        if (StrKit.isEmpty(empId)) {
            return null;
        }
        EmpInfoDO empInfoDO = empInfoService.selectDOById(empId, siteId);
        if (empInfoDO == null || StrKit.isEmpty(empInfoDO.getChannelId())) {
            return null;
        }
        return this.selectById(empInfoDO.getChannelId(), siteId);
    }

    @Override
    public List<ChannelVO> selectByEmpIds(List<String> empIds, String siteId) {
        if (CollectionUtils.isEmpty(empIds)) {
            return new ArrayList<>();
        }
        List<EmpInfoDO> empInfoDOS = empInfoService.selectDoByIds(empIds);
        if (CollectionUtils.isEmpty(empInfoDOS)) {
            return new ArrayList<>();
        }
        List<String> channelList = empInfoDOS.parallelStream()
                .map(EmpInfoDO::getChannelId).distinct().collect(Collectors.toList());
        if (CollectionUtils.isEmpty(channelList)) {
            return new ArrayList<>();
        }
        return this.selectByIds(channelList, siteId);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public List<HrSiteVO> selectSiteByUserId(String userId) {
        List<HrSiteVO> hrSiteVOList = new ArrayList<>();
        // 管理员
        List<RoleMemberDO> roleMemberDOList = permissionProviderService.selectAllRoleMemberByUserId(userId);
        // 管理员按站点分组
        Map<String, String> siteIdAdminNameMap = new HashMap<>(16);
        roleMemberDOList.parallelStream().collect(Collectors.groupingBy(BaseDO::getSiteId)).forEach((siteId, list) -> {
            // 系统管理员
            boolean anyMatch = roleMemberDOList.parallelStream().anyMatch(roleMemberDO
                    -> "system".equals(roleMemberDO.getSubjectType()));
            if (anyMatch) {
                siteIdAdminNameMap.put(siteId, "超级管理员");
            } else {
                siteIdAdminNameMap.put(siteId, list.get(0).getRoleName());
            }
        });
        // 渠道
        List<ChannelDO> channelDOList = selectByUserId(userId);
        // 渠道站点-渠道id
        Map<String, String> siteIdChannelIdMap = channelDOList.parallelStream()
                .collect(Collectors.toMap(BaseDO::getSiteId, BaseDO::getId, (v1, v2) -> v1));
        // 当天0点
        Date dayStart = DateKit8.getStartTime(new Date());
        // 所有站点信息
        Map<String, SiteDO> siteIdDoMap = adminProviderService.selectSiteMap();

        StopWatch stopWatch = new StopWatch("selectSiteByUserId");
//        List<String> siteList = new ArrayList<>();
//        siteList.add("01F52899496340DE82CD7AB3AE423EC1");
//        for (String siteId : siteList) {
        for (String siteId : siteIdDoMap.keySet()) {
            stopWatch.start("siteId： " + siteId);

            SiteDO siteDO = siteIdDoMap.get(siteId);
            // 过期租户直接过滤
            if (siteDO == null || (siteDO.getExpireDate() != null && siteDO.getExpireDate().getTime() < dayStart.getTime())) {
                stopWatch.stop();
                continue;
            }
            HrSiteVO hrSiteVO = siteDO.to(HrSiteVO.class);
            // 角色名称
            String adminName = siteIdAdminNameMap.get(siteId);
            // 渠道Id
            String channelId = siteIdChannelIdMap.get(siteId);
            // 有权限的公司
            List<ChildCompanyListVO> childCompanyListVOList;
            if (adminName == null) {
                // 非管理员
                if (channelId == null) {
                    // 非管理员及渠道员 不允许登录
                    stopWatch.stop();
                    continue;
                } else {
                    // 有渠道身份为渠道员
                    adminName = "渠道员";
                    hrSiteVO.setChannelId(channelId);
                    List<ChannelCompanyVO> channelCompanyVOList = channelCompanyService.selectByChannelId(channelId, siteId);
                    childCompanyListVOList = channelCompanyService.selectChildCompanyByChannelCompanyList(channelCompanyVOList, siteId);
                    // 非管理员
                    hrSiteVO.setIsAdmin(false);
                }
            } else {
                // 管理员
                // 租户下公司列表
                childCompanyListVOList = childCompanyService.select(new ChildCompanyQuery(), new TokenUser(userId, siteId));
                // 管理员
                hrSiteVO.setChannelId(channelId);
                hrSiteVO.setIsAdmin(true);
            }
            hrSiteVO.setAdminName(adminName);
            hrSiteVO.setType("site");
            // 返回站点层 查询下一层
            if (!CollectionUtils.isEmpty(childCompanyListVOList) && "site".equals(childCompanyListVOList.get(0).getType())) {
                childCompanyListVOList = childCompanyListVOList.get(0).getCompanyList();
            }
            // 是渠道但是没有分管用工单位 跳过
            if (CollectionUtils.isEmpty(childCompanyListVOList)) {
                stopWatch.stop();
                continue;
            }
            hrSiteVO.setChildCompanyListVOList(childCompanyListVOList);
            hrSiteVOList.add(hrSiteVO);

            stopWatch.stop();
        }
        log.info(stopWatch.prettyPrint());
        return hrSiteVOList;
    }

    @Override
    public ChannelDO selectByUserIdAndSite(String userId, String siteId) {
        Example example = new Example(ChannelDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("adminUserId", userId)
                .andEqualTo("siteId", siteId);
        List<ChannelDO> channelDOList = channelDAO.selectByExample(example);
        if (CollectionUtils.isEmpty(channelDOList)) {
            return null;
        }
        return channelDOList.get(0);
    }

    private List<ChannelDO> selectByUserId(String userId) {
        Example example = new Example(ChannelDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("adminUserId", userId);
        return channelDAO.selectByExample(example);
    }

    @Override
    public List<ChannelDO> selectByUserIdAndSiteId(String userId, String siteId) {
        Example example = new Example(ChannelDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("adminUserId", userId)
                .andEqualTo("siteId", siteId);
        return channelDAO.selectByExample(example);
    }

    @Override
    @Transactional(value = HrConstants.TX, rollbackFor = Exception.class)
    public String channelInfoExport(ChannelQuery channelQuery, TokenUser tokenUser) {
        List<ChannelDO> channelDOList = new ArrayList<>();
        ChannelQuery channelQuery1 = new ChannelQuery();
        if (!StringUtils.isEmpty(channelQuery.getName())) {
            channelQuery1.setName(channelQuery.getName());
        }
        if (channelQuery.getLevel() == 2) {
            channelQuery1.setChannelGroupId(channelQuery.getChannelGroupId());
            for (ChannelListVO channelListVO : select(channelQuery1, tokenUser.getSiteId())) {
                channelDOList.add(channelListVO.to(ChannelDO.class));
            }
        } else if (channelQuery.getLevel() == 1) {
            Integer myJurisdiction = channelGroupJurisdictionService.getMyJurisdiction(tokenUser);
            if (myJurisdiction == 0 || myJurisdiction == 2) {
                channelDOList.addAll(selectDO(channelQuery1, tokenUser.getSiteId()));
            } else {
                List<ChannelGroupUserDO> channelGroupUserDOList = channelGroupUserService.selectGroupByUserId(tokenUser.getUserId(), tokenUser);
                if (!CollectionUtils.isEmpty(channelGroupUserDOList)) {
                    List<String> groupIds = channelGroupUserDOList.stream().map(ChannelGroupUserDO::getChannelGroupId).collect(Collectors.toList());
                    channelQuery1.setChannelGroupIdList(groupIds);
                    List<ChannelListVO> select = select(channelQuery1, tokenUser.getSiteId());
                    for (ChannelListVO channelListVO : select) {
                        channelDOList.add(channelListVO.to(ChannelDO.class));
                    }
                }
            }
            if (myJurisdiction == 1) {
                ChannelQuery channelQuery2 = new ChannelQuery();
                if (!StringUtils.isEmpty(channelQuery.getName())) {
                    channelQuery2.setName(channelQuery.getName());
                }
                channelQuery2.setChannelGroupId(HrConstants.DEFAULT);
                List<ChannelListVO> select = select(channelQuery2, tokenUser.getSiteId());
                for (ChannelListVO channelListVO : select) {
                    channelDOList.add(channelListVO.to(ChannelDO.class));
                }
            }

        }
        List<ChannelInfoExportVO> channelInfoExportVOList = new ArrayList<>();
        //查询所有渠道分组和所属管理员
        //查出所有分组
        Map<String, ChannelExportVO> stringChannelExportVOMap = new HashMap<>();
        ChannelGroupQuery channelGroupQuery = new ChannelGroupQuery();
        channelGroupQuery.setLevel(2);
        List<ChannelGroupListVO> select = channelGroupService.select(channelGroupQuery, tokenUser.getSiteId());
        ChannelGroupListVO channelGroupListVO = new ChannelGroupListVO();
        channelGroupListVO.setId("DEFAULT");
        channelGroupListVO.setName("默认分组");
        select.add(0, channelGroupListVO);
        for (ChannelGroupListVO groupListVO : select) {
            ChannelGroupUserQuery channelGroupUserQuery = new ChannelGroupUserQuery();
            channelGroupUserQuery.setGroupId(groupListVO.getId());
            if ("默认分组".equals(groupListVO.getName())) {
                channelGroupUserQuery.setJurisdiction(1);
            } else {
                channelGroupUserQuery.setJurisdiction(-1);
            }
            List<ChannelGroupUserListVO> userByGroupId = channelGroupUserService.getUserByGroupId(channelGroupUserQuery, tokenUser);
            ChannelExportVO channelExportVO = new ChannelExportVO();
            channelExportVO.setGroupName(groupListVO.getName());
            if (!CollectionUtils.isEmpty(userByGroupId)) {
                String managers = userByGroupId.stream().map(ChannelGroupUserListVO::getUserName).collect(Collectors.joining(","));
                channelExportVO.setManagers(managers);
            }
            stringChannelExportVOMap.put(groupListVO.getId(), channelExportVO);

        }
        for (ChannelDO channelDO : channelDOList) {
            ChannelInfoExportVO channelInfoExportVO;
            channelInfoExportVO = channelDO.to(ChannelInfoExportVO.class);
            if (!StringUtils.isEmpty(channelDO.getAddress())) {
                String[] split = channelDO.getAddress().split(",");
                if (split.length > 1) {
                    channelInfoExportVO.setAddress(split[1]);
                } else {
                    channelInfoExportVO.setAddress("");
                }
            }
            if (stringChannelExportVOMap.containsKey(channelDO.getChannelGroupId())) {
                ChannelExportVO channelExportVO = stringChannelExportVOMap.get(channelDO.getChannelGroupId());
                channelInfoExportVO.setChannelGroupName(channelExportVO.getGroupName());
                channelInfoExportVO.setGroupManager(channelExportVO.getManagers());
            }
            channelInfoExportVOList.add(channelInfoExportVO);
        }
        return ExcelKit.exportExcel("ChannelInfo", "渠道信息", ChannelInfoExportVO.class, channelInfoExportVOList);
    }

    @Override
    public ChannelVO selectByIdCard(String idCard, TokenUser tokenUser) {
        Example example = new Example(ChannelDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", tokenUser.getSiteId())
                .andEqualTo("idcard", idCard);
        List<ChannelDO> channelDOS = channelDAO.selectByExample(example);
        if (CollectionUtils.isEmpty(channelDOS)) {
            return null;
        }
        return channelDOS.get(0).to(ChannelVO.class);
    }

    /**
     * 根据查询参数，构建example
     *
     * @param channelQuery 查询参数
     * @param siteId       所属站点id
     * @return example
     */
    private Example buildExample(ChannelQuery channelQuery, String siteId) {
        Example example = new Example(ChannelDO.class);
        example.and()
                .andEqualTo("valid", true)
                .andEqualTo("siteId", siteId);
        if (channelQuery.getName() != null) {
            example.and()
                    .andLike("name", "%" + channelQuery.getName() + "%")
                    .orLike("phone", "%" + channelQuery.getName() + "%")
                    .orLike("idcard", "%" + channelQuery.getName() + "%");
        }
        if (channelQuery.getAdminUserId() != null) {
            example.and().andEqualTo("adminUserId", channelQuery.getAdminUserId());
        }
        if (!StringUtils.isEmpty(channelQuery.getChannelGroupId())) {
            if (HrConstants.DEFAULT.equals(channelQuery.getChannelGroupId())) {
                example.and().orEqualTo("channelGroupId", channelQuery.getChannelGroupId()).orIsNull("channelGroupId");
            } else {
                example.and().andEqualTo("channelGroupId", channelQuery.getChannelGroupId());
            }
        }
        if (!CollectionUtils.isEmpty(channelQuery.getChannelGroupIdList())) {
            example.and().andIn("channelGroupId", channelQuery.getChannelGroupIdList());
        }
        if (!StringUtils.isEmpty(channelQuery.getPhone())) {
            example.and().andEqualTo("phone", channelQuery.getPhone());
        }
        // 排序
        ExampleKit.setExampleOrder(example, channelQuery.getOrders());
        return example;
    }
}




